<?php
namespace App\DesignPattern\Adapter;

use App\DesignPattern\Adapter\DbAdapter;

class DbPdo implements DbAdapter
{
    private $_pdo = null;

    public function __construct($host, $user, $pwd, $dbname, $port = null, $charset = "utf8", array $opts = null)
    {
        $socket = isset($opts['socket']) ? $opts['socket'] : null;
        $opts = isset($opts['opts']) ? $opts['opts'] : [];
        $dsn = "mysql:host={$host};dbname={$dbname}";
        if(!empty($port)){
            $dsn .= ";port={$port}";
        }
        if(!empty($socket)){
            $dsn .= ";unix_socket={$socket}";
        }
        if(!empty($charset)){
            $dsn  .= ";charset={$charset}";
        }
        try{
            if(!empty($opts)){
                $this->_pdo = new \PDO($dsn, $user, $pwd, $opts);
            }else{
                $this->_pdo = new \PDO($dsn, $user, $pwd);
            }
        }catch(\PDOException $e){
            throw new \Exception($e->getMessage());
        }
    }

    public function __destruct()
    {
        unset($this->_pdo);
    }

    public function prototype()
    {
        return $this->_pdo;
    }

    public function query($sql, array $params = [], callable $callback = null)
    {
        $stmt = $this->_pdo->prepare($sql);
        if($stmt){
            if(!empty($params)){
                $result = $stmt->execute($params); //绑定参数
            }else{
                $result = $stmt->execute();
            }
            if($result){
                if(stripos($sql, "INSERT") === 0 || stripos($sql, "REPLACE") === 0){
                    $id = $this->_pdo->lastInsertId(); //@todo lastInsertId支持name参数
                    return $id; //返回自增ID
                }elseif(stripos($sql, "SELECT") === 0){
                    if($callback !== null){
                        while($assoc = $stmt->fetch(\PDO::FETCH_ASSOC, \PDO::FETCH_ORI_NEXT)){
                            $callback($assoc);
                        }
                        $stmt->closeCursor();
                    }else{
                        $arr = $stmt->fetchAll(\PDO::FETCH_ASSOC);
                        $stmt->closeCursor();
                        return $arr; //返回数组
                    }
                }else{
                    $rows = $stmt->rowCount();
                    return $rows; //返回受影响条数
                }
            }else{
                return false;
            }
        }else{
            return false;
        }
    }
}